// Copyright 2007-2008 Rory Plaire (codekaizen@gmail.com)

using System;
using System.Collections.Generic;

namespace NPack.Interfaces
{
    /// <summary>
    /// Provides the interface for linearly transforming a matrix.
    /// </summary>
    /// <typeparam name="T">Type of component in the matrix.</typeparam>
    public interface ITransformMatrix<T> : IMatrix<T>
        where T : IEquatable<T>, IComparable<T>, IComputable<T>, IConvertible
    {
        /// <summary>
        /// Scales the matrix by the given <paramref name="amount"/> in all orthoganal columns.
        /// </summary>
        /// <param name="amount">Amount to scale by.</param>
        void Scale(T amount);

        /// <summary>
        /// Scales the matrix by the given <paramref name="amount"/> in all orthoganal columns.
        /// </summary>
        /// <param name="amount">Amount to scale by.</param>
        /// <param name="order">Order in which to apply the operation.</param>
        void Scale(T amount, MatrixOperationOrder order);

        /// <summary>
        /// Scales the matrix by the given vector <paramref name="scaleVector"/>.
        /// </summary>
        /// <param name="scaleVector">
        /// A vector with scaling components which 
        /// correspond to the affine transform dimensions.
        /// </param>
        void Scale(IVector<T> scaleVector);

        /// <summary>
        /// Scales the matrix by the given vector <paramref name="scaleVector"/>.
        /// </summary>
        /// <param name="scaleVector">
        /// A vector with scaling components which 
        /// correspond to the affine transform dimensions.
        /// </param>
        /// <param name="order">Order in which to apply the operation.</param>
        void Scale(IVector<T> scaleVector, MatrixOperationOrder order);

        /// <summary>
        /// Applies a shear to the transform.
        /// </summary>
        /// <param name="shearVector">The vector used to compute the shear.</param>
        void Shear(IVector<T> shearVector);

        /// <summary>
        /// Applies a skew (same as shear) to the transform.
        /// </summary>
        /// <param name="skewVector">The vector used to compute the shear.</param>
        //void Skew(IVector<T> skewVector);
        /// <summary>
        /// Applies a shear (same as shear) to the transform.
        /// </summary>
        /// <param name="skewVector">The vector used to compute the shear.</param>
        /// <param name="order">Order in which to apply the operation.</param>
        //void Skew(IVector<T> skewVector, MatrixOperationOrder order);

        /// <summary>
        /// Applies a shear to the transform.
        /// </summary>
        /// <param name="shearVector">The vector used to compute the shear.</param>
        /// <param name="order">Order in which to apply the operation.</param>
        void Shear(IVector<T> shearVector, MatrixOperationOrder order);

        /// <summary>
        /// Rotates the affine transform around the given <paramref name="axis"/>.
        /// </summary>
        /// <param name="axis">
        /// The axis to rotate around. May be an addition of the basis vectors.
        /// </param>
        /// <param name="radians">Angle to rotate through.</param>
        void RotateAlong(IVector<T> axis, Double radians);

        /// <summary>
        /// Rotates the affine transform around the given <paramref name="axis"/>.
        /// </summary>
        /// <param name="axis">
        /// The axis to rotate around. May be an addition of the basis vectors.
        /// </param>
        /// <param name="radians">Angle to rotate through.</param>
        /// <param name="order">Order in which to apply the operation.</param>
        void RotateAlong(IVector<T> axis, Double radians, MatrixOperationOrder order);

        /// <summary>
        /// Applies this transform to the given <paramref name="input"/> matrix.
        /// </summary>
        /// <param name="input">Matrix to transform.</param>
        /// <returns>
        /// The multiplication of this transform matrix with the input matrix.
        /// </returns>
        IMatrix<T> TransformMatrix(IMatrix<T> input);

        ///// <summary>
        ///// Applies this transform to the given <paramref name="input"/> matrix in place.
        ///// </summary>
        ///// <param name="input">Matrix to transform.</param>
        ///// <returns>
        ///// The multiplication of this transform matrix with the input matrix.
        ///// </returns>
        //void TransformMatrix(T[][] input);

        /// <summary>
        /// Applies this transform to the given <paramref name="input"/> vector.
        /// </summary>
        /// <param name="input">Vector to transform.</param>
        /// <returns>
        /// The multiplication of this transform matrix with the input vector.
        /// </returns>
        IVector<T> TransformVector(IVector<T> input);

        /// <summary>
        /// Applies this transform to the given <paramref name="input"/> vector in place.
        /// </summary>
        /// <param name="input">Vector to transform.</param>
        void TransformVector(T[] input);

        /// <summary>
        /// Applies this transform to the given <paramref name="input"/> vectors.
        /// </summary>
        /// <param name="input">Set of vectors to transform.</param>
        /// <returns>
        /// The multiplication of this transform matrix with each of the input vectors.
        /// </returns>
        IEnumerable<IVector<T>> TransformVectors(IEnumerable<IVector<T>> input);

        /// <summary>
        /// Applies this transform to the given <paramref name="input"/> vectors in place.
        /// </summary>
        /// <param name="input">Set of vectors to transform.</param>
        void TransformVectors(IEnumerable<T[]> input);
    }
}